#include "mywidget.h"
#include "ui_mywidget.h"

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    // ui及控件布局，随窗口大小变化而变化
    this->setLayout(ui->myWd_verlLayout);

    // 手动连接信号和槽：下拉列表中选择编码方式
    // 通过捕捉下拉列表变化的信号，来实现编码方式的选择改变
    connect(ui->comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
            this, [this](int) { this->on_currentIndexChanged(); });

    // 通过捕捉textEdit的光标变化的信号，来实现显示当前的行和列
    connect(ui->myTextEdit,&QTextEdit::cursorPositionChanged,this,&MyWidget::on_cursorPositionChanged);

    // 优化8：添加快捷键
    // ctrl + o 打开文件
    QShortcut *sc_open = new QShortcut(QKeySequence(tr("Ctrl+O")),this);
    // ctrl + s 关闭文件
    QShortcut *sc_save = new QShortcut(QKeySequence(tr("Ctrl+s")),this);
    // ctrl + shift +c 关闭文件或清空文本编辑
    QShortcut *sc_clear_close = new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C),this); // 枚举写法
    // ctrl + = 放大字体
    QShortcut *sc_zoomin = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus), this);
    // ctrl + - 缩小字体
    QShortcut *sc_zoomout = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus), this);
    // 连接信号和槽
    connect(sc_open,&QShortcut::activated,this,&MyWidget::on_openFileBtn_clicked);
    connect(sc_save,&QShortcut::activated,this,&MyWidget::on_saveFileBtn_clicked);
    connect(sc_clear_close,&QShortcut::activated,this,&MyWidget::on_closeFileBtn_clicked);

    // 优化9：使用自带的槽函数，放大和缩小字体
    connect(sc_zoomin,&QShortcut::activated,[this](){ // [this]，允许lambda访问MyWidget类的成员（如ui）
        ui->myTextEdit->zoomIn(1);
    });
    connect(sc_zoomout,&QShortcut::activated,[this](){
        ui->myTextEdit->zoomOut(1);
    });
}

MyWidget::~MyWidget()
{
    file.close();
    delete ui;  
}

/* 关于信号与槽的注意点
    // 手动连接按钮的信号和槽
    connect(ui->openFileBtn,SIGNAL(clicked()),this,SLOT(on_openFileBtn_clicked()));
    // 自动连接信号与槽，槽函数命名符合规范（如 on_openFileBtn_clicked()），所以 Qt 会自动连接一次
    void MyWidget::on_openFileBtn_clicked()
*/

// 打开文件，并且读取文件中的到文本框显示
void MyWidget::on_openFileBtn_clicked()
{
    // 优化2：优化了反复打开文件时，会显示之前文件的内容
    file.close();
    ui->myTextEdit->clear();

    // 1. 打开文件对话窗口，选择txt文件
    QString filedir = QFileDialog::getOpenFileName(this, tr("Open File"),
                                                   txt_dir,
                                                   tr("Text Files (*.txt)"));
    // 2. 打开文件
    file.setFileName(filedir);
    if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
        QMessageBox::critical(this, tr("Error"),tr("Open file error"),QMessageBox::Ok);
        return;
    }
    // 优化1：窗口标题显示当前打开的文件
    this->setWindowTitle(filedir);

    // 3. 设置编码，读取文件内容到 textEdit
    QTextStream in(&file);
    in.setCodec(ui->comboBox->currentText().toStdString().c_str());
    while (!in.atEnd()) {
        QString line = in.readLine(1024);
        ui->myTextEdit->append(line);         // 将内容显示在textEdit
    }
}

// 保存文件，写入文本框的内容
void MyWidget::on_saveFileBtn_clicked()
{
    if(file.isOpen()){
        // 优化3：存在的文件直接保存
        QString cur_file = file.fileName();     // 获得当前文件的路径
        file.close();
        file.setFileName(cur_file);
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){   // 注意，这里要用只写模式，才能覆盖内容
            QMessageBox::critical(this, tr("Error"),tr("Open file error"),QMessageBox::Ok);
            return;
        }
        QTextStream out(&file);                 // 流的内容，刷到文件中
        out.setCodec(ui->comboBox->currentText().toStdString().c_str());
        out << ui->myTextEdit->toPlainText();
    }else{
        // 1. 设置保存位置
        QString filedir = QFileDialog::getSaveFileName(this, tr("Save File"),
                                                       txt_dir+"untitled.txt",     // 保存文件给一个默认名
                                                       tr("Text Files (*.txt)"));
        // 2. 打开文件
        file.setFileName(filedir);
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){
            QMessageBox::critical(this, tr("Error"),tr("Open file error"),QMessageBox::Ok);
            return;
        }
        // 优化1：窗口标题显示当前打开的文件
        this->setWindowTitle(filedir);

        // 3. QTextStream 写入内容，才能保存
        QTextStream out(&file);
        out.setCodec(ui->comboBox->currentText().toStdString().c_str());
        out << ui->myTextEdit->toPlainText();     // 读取文本边界框的纯文本内容
    }
}

// 关闭当前文件
void MyWidget::on_closeFileBtn_clicked()
{
    // 优化7：清除或者关闭文件提示
    int ret = QMessageBox::warning(this, tr("clear or close file"),
                                   tr("Do you want to clear the content or close the txt file?"),
                                   QMessageBox::Save | QMessageBox::Discard
                                   | QMessageBox::Cancel,
                                   QMessageBox::Save);
    switch (ret) {
    case QMessageBox::Save:
        // Save was clicked
        on_saveFileBtn_clicked();    // 保存文件
        ui->myTextEdit->clear();      // 清空文本编辑器
        break;
    case QMessageBox::Discard:       // discard，弃牌，丢弃
        // 清空
        if(file.isOpen()){
            file.close();               // 关闭文件
            ui->myTextEdit->clear();      // 清空文本编辑器

            // 优化1：窗口标题不显示当前打开的文件，因为文件已经关闭了
            this->setWindowTitle("MikeNotepad");
        }
        ui->myTextEdit->clear();      // 清空文本编辑器
        break;
    case QMessageBox::Cancel:
        // Cancel was clicked
        break;
    default:
        // should never be reached
        break;
    }
}

//  选择下拉列表时
void MyWidget::on_currentIndexChanged()
{
    // 1. 先清空文本框
    ui->myTextEdit->clear();
    // 2. 文件打开，读取内容
    if(file.isOpen()){
        // 优化4：
        // 如何解决：textEdit输入内容，再保存文件时，切换编码模式后，程序崩溃的问题
        // 原因：下面是读，但是保存的时候用的是WriteOnly
        QString cur_file = file.fileName();
        file.close();
        file.setFileName(cur_file);
        if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
            QMessageBox::critical(this, tr("Error"),tr("Open file error"),QMessageBox::Ok);
            return;
        }
        file.seek(0);           // 读取前，把光标放到文件开头
        QTextStream in(&file);
        in.setCodec(ui->comboBox->currentText().toStdString().c_str());
        while (!in.atEnd()) {
            QString line = in.readLine(1024);
            ui->myTextEdit->append(line);         // 将内容显示在textEdit
        }
    }
}

// 光标变化
void MyWidget::on_cursorPositionChanged()
{
    // 优化5和6：显示当前光标的位置，同时让该行高亮
    // 获取当前textEdit的光标
    QTextCursor cursor = ui->myTextEdit->textCursor();

    // 显示行号和列号
    QString column = QString::number(cursor.columnNumber() + 1);
    QString row = QString::number(cursor.blockNumber() + 1);
    ui->label->setText(row + "行" + column + "列");

    // 设置当前行高亮
    QList<QTextEdit::ExtraSelection> extraSelections;  // 类似于  QList<int> int_list
    QTextEdit::ExtraSelection selection;               // 然后    int int_data

    // 设置选择范围为当前整行
    selection.cursor = cursor;

    // 设置高亮格式
    QTextCharFormat format;
    format.setBackground(QColor(200, 255, 200));       // 使用更明显的浅绿色
    // 方法2
    // 设置整行显示
    format.setProperty(QTextFormat::FullWidthSelection,true);
    selection.format = format;

    extraSelections.append(selection);                 // 最后 int_list.append(int_data)
    ui->myTextEdit->setExtraSelections(extraSelections);
}
/*
高亮方法1
    // 设置选择范围为当前整行
    cursor.movePosition(QTextCursor::StartOfLine);    // 方法1
    selection.cursor = cursor;
    selection.cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);

    // 设置高亮格式
    QTextCharFormat format;
    format.setBackground(QColor(200, 255, 200)); // 使用更明显的浅绿色
    selection.format = format;
*/
